package generator;

import genes.AmbiguityCodes;
import genes.Codon;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import generator.Strain;



public class Quartet {
	

	public Strain strain1;
	public Strain strain2;
	public Strain strain3;
	public Strain strain4;
	int[] i;
	public int divergence;
	
	
	
	public Quartet(int[] strainId) throws IOException{
		
		StrainPicker sp= new StrainPicker();
		String[] temp=sp.PickStrains(strainId);

		i= sp.getPicked();
//		System.out.println(i[0]);
		this.strain1=new Strain(temp[0]);
		this.strain2=new Strain(temp[1]);
		this.strain3=new Strain(temp[2]);
		this.strain4=new Strain(temp[3]);
	
		

	
	    removeNonSilentMutations();
		removeAmbiguityCodes();
		this.divergence=this.setDivergenceAge();

	}

	public int setDivergenceAge(){
	int[] hds= new int[6];
	hds[0]= this.strain1.hammingDist(this.strain2.getSequence());
	hds[1]= this.strain1.hammingDist(this.strain3.getSequence());
	hds[2]= this.strain1.hammingDist(this.strain4.getSequence());
	hds[3]= this.strain2.hammingDist(this.strain3.getSequence());
	hds[4]= this.strain2.hammingDist(this.strain4.getSequence());
	hds[5]= this.strain3.hammingDist(this.strain4.getSequence());
	Arrays.sort(hds);

	return hds[0];
	
}




public void removeNonSilentMutations() throws IOException{
	List<Codon> s1= this.strain1.getAminoAcidSequence();
	List<Codon> s2= this.strain2.getAminoAcidSequence();
	List<Codon> s3= this.strain3.getAminoAcidSequence();
	List<Codon> s4= this.strain4.getAminoAcidSequence();

	Iterator<Codon> iter1= s1.listIterator();
	Iterator<Codon> iter2= s2.listIterator();
	Iterator<Codon> iter3= s3.listIterator();
	Iterator<Codon> iter4= s4.listIterator();
	HashSet<Integer> CodonPositions = new HashSet<Integer>();
	
	int pos=1;
	
	while(iter1.hasNext()){
		Codon x1= iter1.next();
	//	System.out.println(x1.getCodon());
		Codon x2= iter2.next();
	//	System.out.println(x2.getCodon());
		Codon x3= iter3.next();
	//	System.out.println(x3.getCodon());
		Codon x4= iter4.next();
	//	System.out.println(x4.getCodon());
		if((x1.equals((x2))&&(x2.equals(x3))&&(x3.equals(x4)))){
	//	System.out.println(x1.getCodon()+ x2.getCodon()+x3.getCodon()+x4.getCodon());
		}else{
		//	System.out.println(pos);
			CodonPositions.addAll(getPosOfMutations(pos));
		}
								
			
		
		pos++;
		
	}
//	System.out.println(printListInt(CodonPositions));
	Iterator<Integer> cPosIter= CodonPositions.iterator();

		
	char[] ms1= this.strain1.getSequence().toCharArray();
	char[] ms2= this.strain2.getSequence().toCharArray();
	char[] ms3= this.strain3.getSequence().toCharArray();
	char[] ms4= this.strain4.getSequence().toCharArray();
	cPosIter.next();
	while( cPosIter.hasNext()){
		int remove = cPosIter.next();
	//	System.out.println(remove);
		ms1[remove]=' ';
		ms2[remove]=' ';
		ms3[remove]=' ';
		ms4[remove]=' ';
	
	}
	String l1= "";
	String l2= "";
	String l3= "";
	String l4= "";

	int count=0;
	while(count!=ms1.length){
		if(ms1[count]!=' ')
			l1=l1+ms1[count];
		if(ms2[count]!=' ')
			l2=l2+ms2[count];
		if(ms3[count]!=' ')
			l3=l3+ms3[count];
		if(ms4[count]!=' ')
			l4=l4+ms4[count];
		count++;
	}
	
	
	this.strain1.setSequence(String.valueOf(ms1));
	this.strain2.setSequence(String.valueOf(ms2));
	this.strain3.setSequence(String.valueOf(ms3));
	this.strain4.setSequence(String.valueOf(ms4));
	


}




private List<Integer> getPosOfMutations(int posy) {
	List<Integer> positions= new ArrayList<Integer>();
	int pos=posy*3;
//	positions.add(0);
	positions.add(pos-1);
	positions.add(pos-2);
	positions.add(pos-3);
			return positions;
}

private void removeAmbiguityCodes() throws IOException{

	 String gs1 = strain1.getGeneSequence().geneSequence;
	 String gs2 = strain2.getGeneSequence().geneSequence;
	 String gs3 = strain3.getGeneSequence().geneSequence;
	 String gs4 = strain4.getGeneSequence().geneSequence;

	HashSet<Integer> ambigityPos= new HashSet<Integer>();
	AmbiguityCodes ac= new AmbiguityCodes();
	int posi=0;
	while(gs1.length()!=posi){
		if(ac.isAmbiguityCode(gs1.charAt(posi))){
			ambigityPos.add(posi);
		}
		if(ac.isAmbiguityCode(gs2.charAt(posi))){
			ambigityPos.add(posi);
		}
		if(ac.isAmbiguityCode(gs3.charAt(posi))){
			ambigityPos.add(posi);
		}
		if(ac.isAmbiguityCode(gs4.charAt(posi))){
			ambigityPos.add(posi);
		}
		posi++;
	}
	Iterator<Integer> acIter= ambigityPos.iterator();
	char[] gs1c= gs1.toCharArray();
	char[] gs2c= gs2.toCharArray();
	char[] gs3c= gs3.toCharArray();
	char[] gs4c= gs4.toCharArray();
	while(acIter.hasNext()){
		int remove =acIter.next();
		gs1c[remove]=' ';// or emtpy unicode amy
		gs2c[remove]=' ';// or emtpy unicode amy
		gs3c[remove]=' ';// or emtpy unicode amy
		gs4c[remove]=' ';// or emtpy unicode amy
	}
	this.strain1.setSequence(String.valueOf(gs1c));
	this.strain2.setSequence(String.valueOf(gs2c));
	this.strain3.setSequence(String.valueOf(gs3c));
	this.strain4.setSequence(String.valueOf(gs4c));
	


}

private void removeNonInformativeSites() throws IOException{
	Iterator<Integer> iter =this.getInformativeSites().iterator();
	char[] ts1=this.strain1.getSequence().toCharArray();
	char[] ts2=this.strain2.getSequence().toCharArray();
	char[] ts3=this.strain3.getSequence().toCharArray();
	char[] ts4=this.strain4.getSequence().toCharArray();
	while(iter.hasNext()){
		int remove = iter.next();
		ts1[remove]=' ';
		ts2[remove]=' ';
		ts3[remove]=' ';
		ts4[remove]=' ';
	}


	
	this.strain1.setSequence(String.valueOf(ts1));
	this.strain2.setSequence(String.valueOf(ts2));
	this.strain3.setSequence(String.valueOf(ts3));
	this.strain4.setSequence(String.valueOf(ts4));
	System.out.println("\nUninformative Sites removed");
	System.out.println(this.strain1.getSequence());
	System.out.println(this.strain2.getSequence());
	System.out.println(this.strain3.getSequence());
	System.out.println(this.strain4.getSequence());
}

private String printList(List<String> x){
	Iterator<String> iter= x.iterator();
	String r="";
	while(iter.hasNext()){
		r=r+iter.next();
	//	System.out.println(r);
	}
//	System.out.println(r);
	return r;
}

private String printListInt(List<Integer> x){
	Iterator<Integer> iter= x.iterator();
	String r="";
	while(iter.hasNext()){
		r=r+iter.next();
	//	System.out.println(r);
	}
//	System.out.println(r);
	return r;
}

private String printListInt(HashSet<Integer> x) {
	Iterator<Integer> iter= x.iterator();
	String r="";
	while(iter.hasNext()){
		r=r+","+iter.next();
	//	System.out.println(r);
	}
//	System.out.println(r);
	return r;
	
}

public HashSet<Integer> getInformativeSites(){
	HashSet<Integer> UninformativeSites= new HashSet<Integer>();
	HashSet<Integer> informativeSites= new HashSet<Integer>();
	int pos=0;
	while(pos!=this.strain1.getSequence().length()){
	String currentSite=this.getSite(pos);
	if(!isInformative(currentSite)){
		UninformativeSites.add(pos);
	}
	if(isInformative(currentSite)){
		informativeSites.add(pos);
	}
	pos++;
	}
//	Iterator<Integer> iter=informativeSites.iterator();
//	while(iter.hasNext()){
//		System.out.println(iter.next());
//	}
	return UninformativeSites;
	
}



// test this function
public boolean isInformative(String site){
	return (isTreeOne(site)||isTreeTwo(site)||isTreeThree(site));
}

private String getSite(int pos){
	return (String.valueOf(this.strain1.getSequence().charAt(pos))+
	String.valueOf(this.strain2.getSequence().charAt(pos))+
	String.valueOf(this.strain3.getSequence().charAt(pos))+
	String.valueOf(this.strain4.getSequence().charAt(pos)));
}

public boolean isTreeOne(String site){
	char a= site.charAt(0);
	char b= site.charAt(1);
	char c=site.charAt(2);
	char d= site.charAt(3);
	if(((a==b)&&(c==d))&&((a!=d)&&(b!=c))){
		return true;
	}else return false;
}

public boolean isTreeTwo(String site){
	char a= site.charAt(0);
	char b= site.charAt(1);
	char c=site.charAt(2);
	char d= site.charAt(3);
	if((a==c)&&(b==d)&& !(a==b)&& !(c==d)&&!(a==d)&&!(b==c)){
		return true;
	}else return false;
	
}

public boolean isTreeThree(String site){
	char a= site.charAt(0);
	char b= site.charAt(1);
	char c=site.charAt(2);
	char d= site.charAt(3);
	if((a==d)&&(b==c)&& !(a==b)&&!(a==c)&&!(b==d)&&!(c==d)){
		return true;
	}
	else return false;
}







public int getDivergence(){
	return this.divergence;
}

}
